/*
 *------------------------------------------------------------------------------
 * @File      :    ov5640_dvp.c
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"
#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 5641
#define SNS_NAME  "ov5640_dvp"
#define DEV_TYPE DVP

static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];

static const SNS_REG_S s_aInitRegList[] = {
    { 0x3103, 0x11 }, /* system clock from pad, bit[1] */
    { 0x3008, 0x82 }, /* software reset, bit[7] */
    { SNS_REG_DELAY, 5 },
    { 0x3008, 0x42 }, /* software power down, bit[6] */
    { 0x3103, 0x03 }, /* system clock from PLL, bit[1] */
    { 0x3017, 0xff }, /* FREX, Vsync, HREF, PCLK, D[9:6] output enable */
    { 0x3018, 0xff }, /* D[5:0], GPIO[1:0] output enable */
    { 0x3034, 0x18 }, /* MIPI 8-bit */

    /*
     * PLL root divider, bit[4], PLL pre-divider, bit[3:0],
     * default is 0x13
     */
    { 0x3037, 0x13 },

    /* PCLK root divider, bit[5:4], SCLK2x root divider, bit[3:2] */
    { 0x3108, 0x01 },
    /*
     * SCLK root divider, bit[1:0]
     */
    { 0x3630, 0x36 },
    { 0x3631, 0x0e },
    { 0x3632, 0xe2 },
    { 0x3633, 0x12 },
    { 0x3621, 0xe0 },
    { 0x3704, 0xa0 },
    { 0x3703, 0x5a },
    { 0x3715, 0x78 },
    { 0x3717, 0x01 },
    { 0x370b, 0x60 },
    { 0x3705, 0x1a },
    { 0x3905, 0x02 },
    { 0x3906, 0x10 },
    { 0x3901, 0x0a },
    { 0x3731, 0x12 },
    { 0x3600, 0x08 }, /* VCM control */
    { 0x3601, 0x33 }, /* VCM control */
    { 0x302d, 0x60 }, /* system control */
    { 0x3620, 0x52 },
    { 0x371b, 0x20 },
    { 0x471c, 0x50 },
    { 0x3a13, 0x43 }, /* pre-gain = 1.047x */
    { 0x3a18, 0x00 }, /* gain ceiling */
    { 0x3a19, 0xf8 }, /* gain ceiling = 15.5x */
    { 0x3635, 0x13 },
    { 0x3636, 0x03 },
    { 0x3634, 0x40 },
    { 0x3622, 0x01 },

    /* 50/60Hz detection */
    { 0x3c01, 0x34 }, /* Band auto, bit[7] */
    { 0x3c04, 0x28 }, /* threshold low sum */
    { 0x3c05, 0x98 }, /* threshold high sum */
    { 0x3c06, 0x00 }, /* light meter 1 threshold[15:8] */
    { 0x3c07, 0x08 }, /* light meter 1 threshold[7:0] */
    { 0x3c08, 0x00 }, /* light meter 2 threshold[15:8] */
    { 0x3c09, 0x1c }, /* light meter 2 threshold[7:0] */
    { 0x3c0a, 0x9c }, /* sample number[15:8] */
    { 0x3c0b, 0x40 }, /* sample number[7:0] */
    { 0x3810, 0x00 }, /* Timing Hoffset[11:8] */
    { 0x3811, 0x10 }, /* Timing Hoffset[7:0] */
    { 0x3812, 0x00 }, /* Timing Voffset[10:8] */
    { 0x3708, 0x64 },
    { 0x4001, 0x02 }, /* BLC start from line 2 */
    { 0x4005, 0x1a }, /* BLC always update */
    { 0x3000, 0x00 }, /* enable blocks */
    { 0x3004, 0xff }, /* enable clocks */
    { 0x300e, 0x58 }, /* MIPI power down, DVP enable */
    { 0x302e, 0x00 },
    { 0x4300, 0x30 }, /* YUV 422, YUYV 2018-3-19  YUYV */
    { 0x501f, 0x00 }, /* YUV 422 */
    { 0x440e, 0x00 },
    { 0x5000, 0xa7 }, /* Lenc on, raw gamma on, BPC on, WPC on, CIP on */

    /* AEC target */
    { 0x3a0f, 0x30 }, /* stable range in high */
    { 0x3a10, 0x28 }, /* stable range in low */
    { 0x3a1b, 0x30 }, /* stable range out high */
    { 0x3a1e, 0x26 }, /* stable range out low */
    { 0x3a11, 0x60 }, /* fast zone high */
    { 0x3a1f, 0x14 }, /* fast zone low */

    /* Lens correction for ? */
    { 0x5800, 0x23 },
    { 0x5801, 0x14 },
    { 0x5802, 0x0f },
    { 0x5803, 0x0f },
    { 0x5804, 0x12 },
    { 0x5805, 0x26 },
    { 0x5806, 0x0c },
    { 0x5807, 0x08 },
    { 0x5808, 0x05 },
    { 0x5809, 0x05 },
    { 0x580a, 0x08 },
    { 0x580b, 0x0d },
    { 0x580c, 0x08 },
    { 0x580d, 0x03 },
    { 0x580e, 0x00 },
    { 0x580f, 0x00 },
    { 0x5810, 0x03 },
    { 0x5811, 0x09 },
    { 0x5812, 0x07 },
    { 0x5813, 0x03 },
    { 0x5814, 0x00 },
    { 0x5815, 0x01 },
    { 0x5816, 0x03 },
    { 0x5817, 0x08 },
    { 0x5818, 0x0d },
    { 0x5819, 0x08 },
    { 0x581a, 0x05 },
    { 0x581b, 0x06 },
    { 0x581c, 0x08 },
    { 0x581d, 0x0e },
    { 0x581e, 0x29 },
    { 0x581f, 0x17 },
    { 0x5820, 0x11 },
    { 0x5821, 0x11 },
    { 0x5822, 0x15 },
    { 0x5823, 0x28 },
    { 0x5824, 0x46 },
    { 0x5825, 0x26 },
    { 0x5826, 0x08 },
    { 0x5827, 0x26 },
    { 0x5828, 0x64 },
    { 0x5829, 0x26 },
    { 0x582a, 0x24 },
    { 0x582b, 0x22 },
    { 0x582c, 0x24 },
    { 0x582d, 0x24 },
    { 0x582e, 0x06 },
    { 0x582f, 0x22 },
    { 0x5830, 0x40 },
    { 0x5831, 0x42 },
    { 0x5832, 0x24 },
    { 0x5833, 0x26 },
    { 0x5834, 0x24 },
    { 0x5835, 0x22 },
    { 0x5836, 0x22 },
    { 0x5837, 0x26 },
    { 0x5838, 0x44 },
    { 0x5839, 0x24 },
    { 0x583a, 0x26 },
    { 0x583b, 0x28 },
    { 0x583c, 0x42 },
    { 0x583d, 0xce }, /* lenc BR offset */

    /* AWB */
    { 0x5180, 0xff }, /* AWB B block */
    { 0x5181, 0xf2 }, /* AWB control */
    { 0x5182, 0x00 }, /* [7:4] max local counter, [3:0] max fast counter */
    { 0x5183, 0x14 }, /* AWB advanced */
    { 0x5184, 0x25 },
    { 0x5185, 0x24 },
    { 0x5186, 0x09 },
    { 0x5187, 0x09 },
    { 0x5188, 0x09 },
    { 0x5189, 0x75 },
    { 0x518a, 0x54 },
    { 0x518b, 0xe0 },
    { 0x518c, 0xb2 },
    { 0x518d, 0x42 },
    { 0x518e, 0x3d },
    { 0x518f, 0x56 },
    { 0x5190, 0x46 },
    { 0x5191, 0xf8 }, /* AWB top limit */
    { 0x5192, 0x04 }, /* AWB bottom limit */
    { 0x5193, 0x70 }, /* red limit */
    { 0x5194, 0xf0 }, /* green limit */
    { 0x5195, 0xf0 }, /* blue limit */
    { 0x5196, 0x03 }, /* AWB control */
    { 0x5197, 0x01 }, /* local limit */
    { 0x5198, 0x04 },
    { 0x5199, 0x12 },
    { 0x519a, 0x04 },
    { 0x519b, 0x00 },
    { 0x519c, 0x06 },
    { 0x519d, 0x82 },
    { 0x519e, 0x38 }, /* AWB control */

    /* Gamma */
    { 0x5480, 0x01 }, /* Gamma bias plus on, bit[0] */
    { 0x5481, 0x08 },
    { 0x5482, 0x14 },
    { 0x5483, 0x28 },
    { 0x5484, 0x51 },
    { 0x5485, 0x65 },
    { 0x5486, 0x71 },
    { 0x5487, 0x7d },
    { 0x5488, 0x87 },
    { 0x5489, 0x91 },
    { 0x548a, 0x9a },
    { 0x548b, 0xaa },
    { 0x548c, 0xb8 },
    { 0x548d, 0xcd },
    { 0x548e, 0xdd },
    { 0x548f, 0xea },
    { 0x5490, 0x1d },

    /* color matrix */
    { 0x5381, 0x1e }, /* CMX1 for Y */
    { 0x5382, 0x5b }, /* CMX2 for Y */
    { 0x5383, 0x08 }, /* CMX3 for Y */
    { 0x5384, 0x0a }, /* CMX4 for U */
    { 0x5385, 0x7e }, /* CMX5 for U */
    { 0x5386, 0x88 }, /* CMX6 for U */
    { 0x5387, 0x7c }, /* CMX7 for V */
    { 0x5388, 0x6c }, /* CMX8 for V */
    { 0x5389, 0x10 }, /* CMX9 for V */
    { 0x538a, 0x01 }, /* sign[9] */
    { 0x538b, 0x98 }, /* sign[8:1] */

    /* UV adjsut */
    { 0x5580, 0x06 }, /* saturation on, bit[1] */
    { 0x5583, 0x40 },
    { 0x5584, 0x10 },
    { 0x5589, 0x10 },
    { 0x558a, 0x00 },
    { 0x558b, 0xf8 },
    { 0x501d, 0x40 }, /* enable manual offset of contrast */

    /* CIP */
    { 0x5300, 0x08 }, /* CIP sharpen MT threshold 1 */
    { 0x5301, 0x30 }, /* CIP sharpen MT threshold 2 */
    { 0x5302, 0x10 }, /* CIP sharpen MT offset 1 */
    { 0x5303, 0x00 }, /* CIP sharpen MT offset 2 */
    { 0x5304, 0x08 }, /* CIP DNS threshold 1 */
    { 0x5305, 0x30 }, /* CIP DNS threshold 2 */
    { 0x5306, 0x08 }, /* CIP DNS offset 1 */
    { 0x5307, 0x16 }, /* CIP DNS offset 2 */
    { 0x5309, 0x08 }, /* CIP sharpen TH threshold 1 */
    { 0x530a, 0x30 }, /* CIP sharpen TH threshold 2 */
    { 0x530b, 0x04 }, /* CIP sharpen TH offset 1 */
    { 0x530c, 0x06 }, /* CIP sharpen TH offset 2 */
    { 0x5025, 0x00 },
    { 0x3008, 0x02 }, /* wake up */
};
/*
* VGA 30fps
* YUV VGA 30fps, night mode 5fps
* Input Clock = 24Mhz, PCLK = 56MHz
*/
static const SNS_REG_S s_aYuvVga[] = {
#if (defined CONFIG_ARCH_LOMBO_N7V7_FPGA)
    { 0x3035, 0x41 }, /* FPGA USE PLL, default is 0x11 */
#else
    { 0x3035, 0x11 }, /* IC USE PLL, default is 0x11 */
#endif
    { 0x3036, 0x4A }, /* PLL, default is 0x46 */
    { 0x3c07, 0x08 }, /* light meter 1 threshold [7:0] */
    { 0x3820, 0x41 }, /* Sensor flip off, ISP flip on */
    { 0x3821, 0x07 }, /* Sensor mirror on, ISP mirror on, H binning on */
    { 0x3814, 0x31 }, /* X INC */
    { 0x3815, 0x31 }, /* Y INC */
    { 0x3800, 0x00 }, /* HS */
    { 0x3801, 0x00 }, /* HS */
    { 0x3802, 0x00 }, /* VS */
    { 0x3803, 0x04 }, /* VS */
    { 0x3804, 0x0a }, /* HW (HE) */
    { 0x3805, 0x3f }, /* HW (HE) */
    { 0x3806, 0x07 }, /* VH (VE) */
    { 0x3807, 0x9b }, /* VH (VE) */
    { 0x3808, 0x02 }, /* DVPHO */
    { 0x3809, 0x80 }, /* DVPHO */
    { 0x380a, 0x01 }, /* DVPVO */
    { 0x380b, 0xe0 }, /* DVPVO */
    { 0x380c, 0x07 }, /* HTS */
    { 0x380d, 0x68 }, /* HTS */
    { 0x380e, 0x03 }, /* VTS */
    { 0x380f, 0xd8 }, /* VTS */
    { 0x3813, 0x06 }, /* Timing Voffset */

    /* bit[7:6]: output drive capability[00: 1x, 01: 2x, 10: 3x, 11: 4x] */
    { 0x302c, 0x02 },

    { 0x3618, 0x00 },
    { 0x3612, 0x29 },
    { 0x3709, 0x52 },
    { 0x370c, 0x03 },
    { 0x3a02, 0x17 }, /* 60Hz max exposure, night mode 5fps */
    { 0x3a03, 0x10 }, /* 60Hz max exposure */
    /*
    * banding filters are calculated automatically in camera driver
    */
    { 0x3a08, 0x01 }, /* B50 step */
    { 0x3a09, 0x86 }, /* B50 step */
    { 0x3a0a, 0x01 }, /* B60 step */
    { 0x3a0b, 0x45 }, /* B60 step */
    { 0x3a0e, 0x02 }, /* 50Hz max band */
    { 0x3a0d, 0x03 }, /* 60Hz max band */
    { 0x3a14, 0x17 }, /* 50Hz max exposure, night mode 5fps */
    { 0x3a15, 0x10 }, /* 50Hz max exposure */
    { 0x4004, 0x02 }, /* BLC 2 lines */
    { 0x3002, 0x1c }, /* reset JFIFO, SFIFO, JPEG */
    { 0x3006, 0xc3 }, /* disable clock of JPEG2x, JPEG */
    { 0x4713, 0x03 }, /* JPEG mode 3 */
    { 0x4407, 0x04 }, /* Quantization scale */
    { 0x460b, 0x35 },
    { 0x460c, 0x22 },
    { 0x4837, 0x22 }, /* DVP CLK divider */
    { 0x3824, 0x02 }, /* DVP CLK divider, default is 0x2 */
    /* SDE on, scale on, UV average off, color matrix on, AWB on */
    { 0x5001, 0xa3 },
    { 0x3503, 0x00 }, /* AEC/AGC on */
};

/*
 * 720p 60fps
 * Input Clock = 24Mhz bit rate 672Mbps
 */
static const SNS_REG_S s_aYuv720p[] = {
#if (defined CONFIG_ARCH_LOMBO_N7V7_FPGA)
    { 0x3035, 0x41 }, /* FPGA USE PLL, default is 0x11 */
#else
    { 0x3035, 0x21 }, /* IC USE PLL, default is 0x11 */
#endif
    { 0x3036, 0x54 }, /* PLL */
    { 0x3c07, 0x07 }, /* lightmeter 1 threshold[7:0] */
    { 0x3820, 0x41 }, /* flip */
    { 0x3821, 0x07 }, /* mirror */
    { 0x3814, 0x31 }, /* timing X inc */
    { 0x3815, 0x31 }, /* timing Y inc */
    { 0x3800, 0x00 }, /* HS */
    { 0x3801, 0x00 }, /* HS */
    { 0x3802, 0x00 }, /* VS */
    { 0x3803, 0xfa }, /* VS */
    { 0x3804, 0x0a }, /* HW (HE) */
    { 0x3805, 0x3f }, /* HW (HE) */
    { 0x3806, 0x06 }, /* VH (VE) */
    { 0x3807, 0xa9 }, /* VH (VE) */
    { 0x3808, 0x05 }, /* DVPHO */
    { 0x3809, 0x00 }, /* DVPHO */
    { 0x380a, 0x02 }, /* DVPVO */
    { 0x380b, 0xd0 }, /* DVPVO */
    { 0x380c, 0x07 }, /* HTS */
    { 0x380d, 0x64 }, /* HTS */
    { 0x380e, 0x02 }, /* VTS */
    { 0x380f, 0xe4 }, /* VTS */
    { 0x3813, 0x04 }, /* timing V offset */
    { 0x3618, 0x00 },
    { 0x3612, 0x29 },
    { 0x3709, 0x52 },
    { 0x370c, 0x03 },
    { 0x3a02, 0x02 }, /* 60Hz max exposure */
    { 0x3a03, 0xe0 }, /* 60Hz max exposure */
    /* banding filters are calculated automatically in camera driver */
    { 0x3a08, 0x00 }, /* B50 step */
    { 0x3a09, 0xDD }, /* B50 step */
    { 0x3a0a, 0x00 }, /* B60 step */
    { 0x3a0b, 0xB8 }, /* B60 step */
    { 0x3a0e, 0x03 }, /* 50Hz max band */
    { 0x3a0d, 0x04 }, /* 60Hz max band */

    { 0x3a14, 0x02 }, /* 50Hz max exposure */
    { 0x3a15, 0xe0 }, /* 50Hz max exposure */
    { 0x4004, 0x02 }, /* BLC line number */
    { 0x3002, 0x1c }, /* reset JFIFO, SFIFO, JPG */
    { 0x3006, 0xc3 }, /* disable clock of JPEG2x, JPEG */
    { 0x4713, 0x03 }, /* JPEG mode 3 */
    { 0x4407, 0x04 }, /* Quantization scale */
    { 0x460b, 0x37 },
    { 0x460c, 0x20 },
    { 0x4837, 0x16 }, /* MIPI global timing */
    { 0x3824, 0x02 }, /* PCLK manual divider */
    { 0x302c, 0x42 }, /* bit[7:6]: output drive capability
               * 00: 1x, 01: 2x, 10: 3x, 11: 4x
               */
    { 0x5001, 0x83 }, /* SDE on, CMX on, AWB on */
    { 0x3503, 0x00 }, /* AEC/ AGC on */

};


static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 5},
    {SNS_PWDN,  SNS_UP},
    {SNS_DELAY, 10},
    {SNS_PWDN, SNS_DOWN},
    {SNS_DELAY, 5},
    {SNS_RESET,  SNS_UP},
    {SNS_DELAY, 10},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_PWDN,  SNS_UP},
};

static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = OV5640_DVP_1280_720_30FPS_YUV,
        .enPixelFormat              = PIX_FMT_YUV_SEMIPLANAR_420,
        .stSize                     = {1280, 720},
        .u32Mclock                  = 24000000,
        .enYuvSeq                   = VISS_YUV_SEQ_C1C0C3C2,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,
#if (defined CONFIG_ARCH_LOMBO_N7V7_FPGA)
        .u32FrameRate                = 15,
#else
        .u32FrameRate                = 30,
#endif
        .astRegCfgs[0].pstRegs      = s_aInitRegList,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aInitRegList),
        .astRegCfgs[1].pstRegs      = s_aYuv720p,
        .astRegCfgs[1].u32RegsCnt   = ARRAY_SIZE(s_aYuv720p),
    },
    {
        .enSnsType                  = OV5640_DVP_640_480_30FPS_YUV,
        .enPixelFormat              = PIX_FMT_YUV_SEMIPLANAR_420,
        .stSize                     = {640, 480},
        .u32Mclock                  = 24000000,
        .enYuvSeq                    = VISS_YUV_SEQ_C1C0C3C2,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,
#if (defined CONFIG_ARCH_LOMBO_N7V7_FPGA)
        .u32FrameRate                = 10,
#else
        .u32FrameRate                = 30,
#endif
        .astRegCfgs[0].pstRegs      = s_aInitRegList,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aInitRegList),
        .astRegCfgs[1].pstRegs      = s_aYuvVga,
        .astRegCfgs[1].u32RegsCnt   = ARRAY_SIZE(s_aYuvVga),
    },
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 8;
#if defined(CONFIG_ARCH_LOMBO_N7V7)
    pstSnsState->stI2cInfo.u16I2cBusNum = 3;
#else
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
#endif
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x3C;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{
    EI_U8 u8Tmp[2];
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U16 u16Id;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);

    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x300A, &u8Tmp[0]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x\n", u8Tmp[0]);
        return s32Ret;
    }
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x300B, &u8Tmp[1]);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x,tmp[1]=%x\n", u8Tmp[0], u8Tmp[1]);
        return s32Ret;
    }
    u16Id = (u8Tmp[0] << 8) | u8Tmp[1];
    PRT_VISS_INFO("%s id: 0x%04x\n", SNS_NAME, u16Id);

    if (u16Id != 0x5640) {
        PRT_VISS_ERR("%s ID wrong! (0x%04x != 0x5640)\n", SNS_NAME, u16Id);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    PRT_VISS_ERR("%s CAMERA_Stream*******%d\n", SNS_NAME, bOn);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3019, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }

        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x4800, 0x24);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3019, 0x70);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }

        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x4800, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    }
    return s32Ret;

}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0xa0000000);

    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0x00000000);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsType = pstSnsState->pstSnsAttr;
    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err", SNS_NAME);
            return s32Ret;
        }
    }

    PRT_VISS_INFO("%s writeRegList success", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize           = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat    = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate      = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraOv5640dvpObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = EI_NULL,
    .pfnUnRegisterIspCallback   = EI_NULL,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

